package grimbo.goodwinfooty.server;

import grimbo.goodwinfooty.service.model.FootyMatrix;

import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

public class DatastoreDB implements GoodwinFootyDB {
	private static final String CNAME = DatastoreDB.class.getName();
	private static final Logger log = Logger.getLogger(CNAME);
	private static final String KIND_FOOTY_MATRIX = "FootyMatrix";

	private DatastoreService datastoreService;

	@Override
	public FootyMatrix loadFootyMatrix() {
		final String MNAME = "loadFootyMatrix()";
		final boolean DEBUG = log.isLoggable(Level.FINE);

		if (DEBUG) {
			log.entering(CNAME, MNAME);
		}

		Entity entity = loadEntity();

		if (null == entity) {
			return null;
		}

		Blob blob = (Blob) entity.getProperty(KIND_FOOTY_MATRIX);

		FootyMatrix result = null;

		try {
			result = (FootyMatrix) ByteUtils.bytesToObject(blob.getBytes());
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}

		if (DEBUG) {
			log.exiting(CNAME, MNAME);
		}

		return result;
	}

	private Entity loadEntity() {
		final String MNAME = "loadEntity()";
		final boolean DEBUG = log.isLoggable(Level.FINE);

		Query query = new Query(KIND_FOOTY_MATRIX);
		PreparedQuery pq = datastoreService.prepare(query);
		Iterator<Entity> it = pq.asIterator();

		if (!it.hasNext()) {
			return null;
		}

		Entity entity = it.next();

		if (DEBUG) {
			// +1 as we've already called next() above
			int count = iteratorSize(it) + 1;
			log.fine("Loaded " + count + " entities of type \""
					+ KIND_FOOTY_MATRIX + "\"");
		}

		return entity;
	}

	private int iteratorSize(Iterator it) {
		int count = 0;
		while (it.hasNext()) {
			it.next();
			count++;
		}
		return count;
	}

	@Override
	public void saveFootyMatrix(FootyMatrix footyMatrix) {
		final String MNAME = "saveFootyMatrix(FootyMatrix)";
		final boolean DEBUG = log.isLoggable(Level.FINE);

		if (DEBUG) {
			log.entering(CNAME, MNAME);
		}

		Entity entity = loadEntity();

		if (null == entity) {
			entity = new Entity(KIND_FOOTY_MATRIX);
		}

		try {
			Blob blob = new Blob(ByteUtils.objectToBytes(footyMatrix));
			entity.setProperty(KIND_FOOTY_MATRIX, blob);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		datastoreService.put(entity);

		if (DEBUG) {
			log.exiting(CNAME, MNAME);
		}
	}

	public DatastoreService getDatastoreService() {
		return datastoreService;
	}

	public void setDatastoreService(DatastoreService datastoreService) {
		this.datastoreService = datastoreService;
	}

}
